/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.controlador;
import com.utilidades.*;
import com.modelo.Campo;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.*;
import org.jdom.Element;

/**
 *
 * @author Raul VB
 */
public class AnalizadorQuery 
{
    
    public static void create(String query,String ruta)
    {
        //Definiciones regulares
        String nombreTabla="(\\w+)"; 
        String tipoDato="(int|varchar\\(\\d+\\)|float|char\\(\\d+\\))\\s(NOT NULL|NULL)";
        String campos="(\\w+\\s"+tipoDato+"(,\\w+\\s"+tipoDato+")*)";
        ///////////////////////////////////////////////////////////////////////
        //EXPRESION FINAL CONSTRUIDA
        String regex="create table "+nombreTabla+"\\s?\\("+campos+"\\)\\;?";
        
        
        Pattern p=Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        Matcher m=p.matcher(query);
        if(m.matches())
        {
            System.out.println("Yeah ha funcionado la expresionr regular");
            /*Sirve para visualizar los grupos
             * Grupo 0 comando completo, grupo 1 nombre de la tabla
             * Grupo 2 Atributos completos
             */            
        }
        else
        {
            System.out.println("Error en la sintaxis");
            return;
        }
        String strCampos=m.group(2);
        String tabla=m.group(1);
        String arrayCampos[]=strCampos.split(",");
        
        /*for(int i= 0; i< arrayCampos.length; i++)
        {
            System.out.println("Campo "+i+" : "+arrayCampos[i]);
        }//Muestra el array de campos ya seccionado.*/
        
        String regexSeccionCampo="(\\w+)\\s+(\\w+)(\\((\\d+)\\))?\\s((NOT NULL|NULL))";
        //Grupo 1 Nombre del campo
        //Grupo 2 tipo de dato
        //Grupo 3 longitud del dato
        //Grupo 4 longitud en numero
        //Grupo 5 NOT NULL ó NULL
        p=Pattern.compile(regexSeccionCampo);
        boolean Null;
        ArrayList<Campo> Campos=new ArrayList<Campo>();
        Campo campo;
        for(int i= 0; i< arrayCampos.length; i++) //Recorremos cada grupo de campos
        {
            //Evaluamos cada campo con sus caracteristicas y extraemos los grupos que nos interesan
            m=p.matcher(arrayCampos[i]);
            if(m.matches())
            {
                for (int j=0; j< m.groupCount(); j++)
                {
                    System.out.println("Grupo "+j+": "+m.group(j));
                }
                System.out.println("Tipo dato "+m.group(2));
                Null=((m.group(5).equals("NULL")==true)?true:false);     
                if(m.group(4)!=null)
                {
                    campo=new Campo(m.group(1), m.group(2), Integer.valueOf(m.group(4)), Null);
                }
                else
                {
                    campo=new Campo(m.group(1), m.group(2), Null);
                }
                Campos.add(campo);
            }
        }
        
        XMLWritter.crearTabla(tabla, Campos,ruta+tabla);
        
        
    }
    
    
    public static void insert(String query,String ruta)
    {
        /*
         * insert into tabla(camsl,mksls) values(kskso,sososo);
         * 
         * insert into
         * (\w+)
         * \\(
         * (\w+(,\w+)*)
         * \\)
         * \\s
         * values\\(
         * (\w+(,\w+)*)
         * 
         */
        //query="insert into EMPLEADO(campo1,campo2,campo3) values('Hola',99,'Otracosa')";
        String tabla="(\\w+)";
        String campos="(\\w+(,\\w+)*)?";
        String valores="(('\\w+'|\\d+)(,('\\w+'|\\d+))*)";
        String regexInsert="insert into\\s*"+tabla+"\\s*(\\("+campos+"\\))?\\s+values\\s*\\("+valores+"\\)\\;?";
        Pattern p= Pattern.compile(regexInsert);
        Matcher m=p.matcher(query);
        String nombreTabla;
        String strCampos;
        String strValores;
        ArrayList<Campo> registros=new ArrayList<Campo>();
        
        /*
         * Grupo 0 Cadena completa
         * Grupo 1 Nombre de la tabla
         * Grupo 2 Nombre de los campos, con todo y parentesis
         * Grupo 3 Nombre de los campos sin parentesis separados por coma
         * Grupo 4 Ultimo campo
         * Grupo 5 Todos los valores separados por coma y con sus respectivas comillas simples
         * Grupo 6 Primer valor
         * Grupo 7 Coma y el ultimo valor con comillas o sin commilas
         */
        if(m.matches())
        {
            for (int i=0;i<m.groupCount(); i++)
            {
                System.out.println("Grupo "+i+" : "+m.group(i));
            }
            nombreTabla=m.group(1);
            strCampos=m.group(3);
            System.out.println("Longitud!!!! "+strCampos);
            strValores=m.group(5);
            
            Element rootTabla=XMLReader.obtenerTabla(nombreTabla, ruta);
            ArrayList<Campo> propiedadesTabla=XMLReader.obtenerPropiedadesTabla(ruta,nombreTabla);
            for(Campo e: propiedadesTabla)
            {
                
                System.out.println("Estamos en el for each:    "+e.toString());
            }
            System.out.println("Fin for each");
            if(strValores==null)
            {
                System.err.println("Error no hay valores para completar el comando insert");
                return;
            }         
            
            if((strCampos==null))
            {
                if(propiedadesTabla.size()!=strValores.split(",").length)
                {
                    System.err.println("Error, Faltan campos por llenar");//ERROR
                    return;//Salimos de la funcion para no seguir haciendo procedimiento
                }
                //PROCEDIMIENTO PARA INSERTAR TODOS LOS VALORES EN LA TABLA
                /*
                 * AQUI PROCEDIMIENTO ES SENCILLO
                 * 
                 */
                return;
            }
            registros=AnalizadorQuery.obtenerCamposFromString(strValores, strCampos, ",");
            if(registros==null)
            {
                System.err.println("La lista de campos no corresponde con la lista de valores");
                return;
            }
            if(validacionCorrespondenciaCamposRegistros(registros,propiedadesTabla))
            {
                //
                System.out.println("Todo correcto!! Se insertara el registro");
                XMLWritter.agregarRegistro(nombreTabla,ruta,registros);
            }
        }
        else
        {
            System.out.println(m.toMatchResult().toString());
            
        }
        
    }
    
    
    
    public static ArrayList<Campo> obtenerCamposFromString(String strValores,String strCampos,String regex)
    {
        ArrayList<Campo> campos= new ArrayList<Campo>();
        String arrayCampos[]=strCampos.split(regex);
        String arrayValores[]=strValores.split(regex);
        Campo campo;
        if(arrayCampos.length!=arrayValores.length)
        {
            System.err.println("Error la lista de valores no corresponde a la lista de campos");
            return null;
        }
        for(int i=0; i < arrayValores.length; i++)
        {
            arrayValores[i]=arrayValores[i].replace("'", "");
        }
        for(int i=0; i < arrayCampos.length;i++)
        {
            campo=new Campo(arrayCampos[i],arrayValores[i]);
            campos.add(campo);
        }
        return campos;
    }
    
    
    public static boolean validacionCorrespondenciaCamposRegistros(ArrayList<Campo> registros, ArrayList<Campo> propiedades)
    {
        boolean result=false;
        for(int i=0; i< registros.size(); i++)
        {
            for(int j=0; j < propiedades.size(); j++)
            {
                
                if(propiedades.get(j).getNombre().equals(registros.get(i).getNombre()))//Coincide el registro con el tipo de campo que le pertenece
                {
                    
                    if(propiedades.get(j).getTipoDato().equals("int"))
                    {
                        try
                        {
                            Integer.valueOf(registros.get(i).getContenido());//El registro se debe poder convertir a entero
                        }catch(Exception e)
                        {
                            return result;//No se pudo convertir, por lo tanto el tipo de valor ingresado
                            //no corresponde con las propiedades de la tabla
                        }
                    }
                    else if(propiedades.get(j).getTipoDato().equals("char"))
                    {
                        int longitud=propiedades.get(j).getLongitud();
                        if(registros.get(i).getContenido().length()>longitud)
                        {
                            return result;
                        }
                    }
                    else if(propiedades.get(j).getTipoDato().equals("varchar"))
                    {
                        int longitud=propiedades.get(j).getLongitud();
                        if(registros.get(i).getContenido().length()>longitud)
                        {
                            return result;
                        }
                    }
                
                }
                
                
            }
        }
        return true;
    }
    
    public static void delete(String query,String ruta)
    {
        int i=0;
        String nomTabla="(\\w+)";
        String atributo="(\\w+)";
        String registro="\\'*(\\w+)\\'*";
        String simbolo="(\\=|\\<|\\>|\\<=|\\>=)";
        //String consultaCreateTable="create\\stable\\s"+nomTabla+"\\s\\(\\n*"+atributo+"\\s"+tipoDato+"\\(*"+longitud+"\\)*\\s"+nulo+"(\\,\\w+)*\\n*\\)\\;?";
        String consultaDelete="delete\\sfrom\\s"+nomTabla+"\\swhere\\s"+atributo+simbolo+registro+"\\;?";
        Pattern delete=Pattern.compile(consultaDelete,Pattern.CASE_INSENSITIVE);
        Matcher del=delete.matcher(query);
        System.out.println(del.matches());
        if(del.matches())
        {
            System.out.println(del.groupCount());
            while(i<=del.groupCount())
            {
                System.out.println(del.group(i));
                i++;
            }
        }
        //Grupo1 Nombre de la Tabla
        //Grupo2 CAMPO
        //Grupo3 Simbolo
        //Grupo4 VALOR
        String nombreTabla=del.group(1);
        String camp=del.group(2);
        String sim=del.group(3);
        String valor=del.group(4);
        System.out.println("\n\n-------VALORES DE LOS GRUPOS ----------"+"\n"+nombreTabla+"\n"+camp+"\n"+sim+"\n"+valor);
        Campo condicion = new Campo(camp,valor);
        System.out.println("\n\n"+condicion.toString());
        XMLWritter.eliminarRegistro(nombreTabla, condicion, ruta, sim);
    }
    
  
    public static void update(String query,String ruta)
    {
       int i=0;
       String nomTabla="(\\w+)";
       String atributo="(\\w+)";
       String simbolo="(\\=|\\<|\\>|\\<=|\\>=)";
       String valor="\\'?(\\w+)\\'?";
       //String consultaCreateTable="create\\stable\\s"+nomTabla+"\\s\\(\\n*"+atributo+"\\s"+tipoDato+"\\(*"+longitud+"\\)*\\s"+nulo+"(\\,\\w+)*\\n*\\)\\;?";
       String consultaUpdate="update\\s"+nomTabla+"\\sset\\s"+atributo+simbolo+valor+"\\swhere\\s"+atributo+simbolo+valor+"\\;?";
       Pattern up=Pattern.compile(consultaUpdate,Pattern.CASE_INSENSITIVE);
       Matcher update=up.matcher(query);
       System.out.println(update.matches());
       if(update.matches()){
           System.out.println(update.groupCount());
           while(i<=update.groupCount()){
       System.out.println(update.group(i));
       i++;
           }
           }
       //Grupo1 Nombre de la Tabla
       //Grupo2 CampoOld
       //Grupo3 SimboloOld
       //Grupo4 VALOROld
       //Grupo2 CampoNew
       //Grupo3 Simbolo
       //Grupo4 VALORNew
       String nombreTabla=update.group(1);
       String campOld=update.group(2);
       String simOld=update.group(3);
       String valorOld=update.group(4);
       String campNew=update.group(5);
       String simNew=update.group(6);
       String valorNew=update.group(7);
       //System.out.println("\n\n-------VALORES DE LOS GRUPOS ----------"+"\n"+nombreTabla+"\n"+camp+"\n"+sim+"\n"+valor);
       Campo condicion1 = new Campo(campOld,valorOld);
       Campo condicion2 = new Campo(campNew,valorNew);
       ArrayList<Campo> campos=new ArrayList<Campo>();
       campos.add(condicion1);
       System.out.println("\n\n"+condicion1.toString()+"\n\n"+condicion2.toString());
       XMLWritter.actualizarRegistros(nombreTabla, campos, condicion2, simNew, ruta);
    }
    
    public static ArrayList<Element> select(String query,String ruta)
    {
        /*
            select
            (\*|\w+(,\w+))
            \s+
            from
            \s+
            (\w+)
            (\s+
            where
            \s+
            (\w+)
            (=)
            ('\\w+'|\\d+)
            (\s+
            (AND|OR|and|or)
            (\w+)
            (=)
            ('\\w+'|\\d+)
            ))
         * 
         */
        //query="select Nombre,Apellido,Ciudad from EMPLEADO";
        
        String regexSelect="select\\s+((\\*)|(\\w+(,\\w+)*)+)\\s*from\\s+(\\w+)(\\s+where\\s+(\\w+)(=|>|<|>=|<=)('\\w+'|\\d+)(\\s+(AND|OR|and|or)\\s+(\\w+)(=|>|<|>=|<=)('\\w+'|\\d+))?)?\\;?";
        Pattern p= Pattern.compile(regexSelect);
        Matcher m=p.matcher(query);        
        ArrayList<Campo> registros=new ArrayList<Campo>();
        /*
         * Grupo 0 : select campo1,campo2,campo3 from EMPLEADO where campo1=99 and campo2=67
         * Grupo 1 : campo1,campo2,campo3
         * Grupo 2 : null (*)
         * Grupo 3 : campo1,campo2,campo3
         * Grupo 4 : ,campo3
         * Grupo 5 : EMPLEADO
         * Grupo 6 :  where campo1=99 and campo2=67
         * Grupo 7 : campo1
         * Grupo 8 : =
         * Grupo 9 : 99
         * Grupo 10 :  and campo2=67
         * Grupo 11 : and
         * Grupo 12 : campo2
         * Grupo 13 : =
         * Grupo 14 : 67
         */
        
        if(m.matches())
        {
            Campo condicion1;
            Campo condicion2;
            ArrayList<Element> resultados=new ArrayList<Element>();
            ArrayList<Element> resultadosCondicion1;
            ArrayList<Element> resultadosCondicion2;
            String nombreTabla=m.group(5);
            String todosCampos=m.group(2);
            String camposSeleccionados=m.group(3);
            String campoCondicion1=m.group(7);
            String simboloCondicion1=m.group(8);
            String ValorCondicion1=m.group(9);
            String operadorLogico=m.group(11);//SI NO ES NULA LA CADENA
                                                //QUIERE DECIR QUE LAS VARIABLES DE CONDICION2 NO SON NULAS
            String campoCondicion2=m.group(12);
            String simboloCondicion2=m.group(13);
            String ValorCondicion2=m.group(14);
            for (int i=0;i<=m.groupCount(); i++)
            {
                System.out.println("Grupo "+i+" : "+m.group(i));
            }
            //PRIMERO EXTRAER TODOS LOS REGISTROS QUE SE SOLICITAN.
            //PARA ELLO EXTRAEREMOS TODOS Y POSTERIORMENTE SELECCIONAREMOS
            //LOS QUE SIRVEN
            Element root=XMLReader.obtenerTabla(nombreTabla, ruta);
            List<Element> eRegistros=root.getChild("Registros").getChildren();
            if(m.group(6)!=null)//Quiere decir que hay una condicion al menos
            {
                ValorCondicion1=ValorCondicion1.replace("'", "");
                condicion1=new Campo(campoCondicion1,ValorCondicion1);
                resultadosCondicion1=obtenerRegistrosPorCondicion(condicion1,eRegistros,simboloCondicion1);
                
                if(m.group(10)!=null)
                {
                    ValorCondicion2=ValorCondicion2.replace("'", "");
                    condicion2=new Campo(campoCondicion2,ValorCondicion2);
                    resultadosCondicion2=obtenerRegistrosPorCondicion(condicion2,eRegistros,simboloCondicion2);
                    operadorLogico=operadorLogico.toLowerCase();
                    if(operadorLogico.equals("and"))
                    {
                        //REPRESENTA UN ELEMENTO "REGISTRO"
                        resultados=interseccionResultados(resultadosCondicion1,resultadosCondicion2);                        
                        imprimirElementos(resultados);
                        resultados=seleccionarRegistros(resultados,camposSeleccionados);
                        System.out.println("La ultima impresion antes de mostrar los resultados\n\t");
                        imprimirElementos(resultados);
                        return resultados;
                    }
                    else if(operadorLogico.equals("or"))
                    {
                        resultados=unionResultados(resultadosCondicion1,resultadosCondicion2);
                        imprimirElementos(resultados);
                        resultados=seleccionarRegistros(resultados,camposSeleccionados);
                        imprimirElementos(resultados);
                        return resultados;
                    }
                    
                }
                else
                {
                    resultadosCondicion1=seleccionarRegistros(resultados,camposSeleccionados);
                    return resultadosCondicion1;
                }
            }
            else//NO HAY NINGUN WHERE
            {
                for(Element e:eRegistros)
                {
                    resultados.add(e);
                }
                if(todosCampos!=null)
                {
                    return resultados;
                }
                else if(camposSeleccionados!=null)
                {
                    resultados=seleccionarRegistros(resultados,camposSeleccionados);
                    return resultados;
                }
                
            }
            //resultados=seleccionarRegistros(resultados,String campos);
            
        }
        else
        {
            System.out.println(m.toMatchResult().toString());
        }
        
        return null;//debe cambiar el retorno solo es para que no marqu error
    }
    
    public static ArrayList<Element> obtenerRegistrosPorCondicion(Campo condicion,List<Element> registros,String simbolo)
    {
        boolean isInteger=false;
        int valor=0;
        ArrayList<Element> resultados=new ArrayList<Element>();
        try
        {
            valor=Integer.valueOf(condicion.getContenido());            
            isInteger=true;
        }catch(Exception e)
        {
            isInteger=false;                    
            //return null;
        }
        if(!isInteger && simbolo.equals("="))
        {System.out.println("No es entero");
            for(int i=0; i < registros.size(); i++)
            {
                //System.out.println("El campo es: "+registros.get(i).getChild(condicion.getNombre()).getText());
                //System.out.println("La condicion es: "+condicion.getContenido());
                if(registros.get(i).getChild(condicion.getNombre()).getText().equals(condicion.getContenido()))
                {
                    //System.out.println("Entro a la condicion");
                    resultados.add(registros.get(i));
                }
            }
        }
        else if(isInteger)
        {
            int aux;
            for(int i=0; i < registros.size(); i++)
            {
                if(registros.get(i).getChild(condicion.getNombre()).equals(condicion.getContenido()) && simbolo.equals("="))
                {
                    resultados.add(registros.get(i));
                }
                else
                {
                    try
                    {
                        aux=Integer.valueOf(registros.get(i).getChild(condicion.getNombre()).getText());
                        if(aux>valor && simbolo.equals(">"))
                        {
                            resultados.add(registros.get(i));
                        }
                        else if(aux<valor && simbolo.equals("<"))
                        {
                            resultados.add(registros.get(i));
                        }
                        else if(aux>=valor && simbolo.equals(">="))
                        {
                            resultados.add(registros.get(i));
                        }
                        else if(aux<=valor && simbolo.equals("<="))
                        {
                            resultados.add(registros.get(i));
                        }
                    }catch(Exception e)
                    {
                        e.printStackTrace();
                        System.err.println("No es posible realizar el comando, los tipos de valores no coinciden");
                    }
                }
            }
        }
        
        return resultados;
    }
    
    
    public static ArrayList<Element> interseccionResultados(ArrayList<Element> resultados1,ArrayList<Element> resultados2)
    {
        ArrayList<Element> resultados=new ArrayList<Element>();
        for(int i=0; i< resultados1.size(); i++)
        {
            for(int j=0; j< resultados2.size(); j++)
            {
                if(resultados1.get(i)==resultados2.get(j))
                {
                    resultados.add(resultados1.get(i));
                    System.out.println("Hay intersecion");
                    continue;
                }
            }
        }
        return resultados;
    }
    public static ArrayList<Element> unionResultados(ArrayList<Element> r1, ArrayList<Element> r2)
    {
        ArrayList<Element> resultados=new ArrayList<Element>();
        for(Element e:r1)
        {
            resultados.add(e);
        }
        
        for(Element e:r2)
        {
            resultados.add(e);
        }          
        return resultados;
    }
    
    public static void imprimirElementos(ArrayList<Element> e)
    {
        List<Element> aux;
        for(int i=0; i < e.size(); i++)
        {
            for(int j=0; j< e.get(i).getChildren().size();j++)
            {
                aux=e.get(i).getChildren();
                System.out.println(aux.get(j).getName()+" :"+aux.get(j).getText());
            }
            System.out.println("\n");
        }
    }
    
    public static ArrayList<Element> seleccionarRegistros(ArrayList<Element> r1,String campos)
    {
        if(campos==null)
        {
            return r1;
        }
        ArrayList<Element> resultados=new ArrayList<Element>();
        List<Element> eCampos;
        ArrayList<Element> RegistrosInnecesarios=new ArrayList<Element>();
        String arrayCampos[]=campos.split(",");
        for(int i=0; i< r1.size();i++)
        {
            eCampos=r1.get(i).getChildren();
            for(int j=0; j < eCampos.size();j++)
            {
                for(int k=0; k < arrayCampos.length;k++)
                {
                    if(eCampos.get(j).getName().equals(arrayCampos[k]))
                    {
                        resultados.add(eCampos.get(j));
                    }
                }
            }
        }
        
        boolean eliminar=false;
        for(int i=0; i< r1.size();i++)
        {
            eCampos=r1.get(i).getChildren();
            for(int j=0;j< eCampos.size();j++)
            {
                System.out.println("Ultima validacion: "+eCampos.get(j).getName());
                if(!resultados.contains(eCampos.get(j)))
                {
                    System.out.println("No se contiene en la lsita "+eCampos.get(j).getName());
                    RegistrosInnecesarios.add(eCampos.get(j));
                }
            }
        }
        for(Element e:RegistrosInnecesarios)
        {
            e.detach();
        }
        return r1;
    }
    
}
